﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using System.Security.Principal;

namespace Flash.Internal
{
    internal static class ReflectionHelper
    {
        internal static MethodInfo FindActionMethod(Type type, string action, Dictionary<string, string> parameters)
        {
            var method = type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
                .Where(x => Attribute.IsDefined(x, typeof(FlashActionAttribute))
                    && action == (x.GetAttributeInfo<FlashActionAttribute>().MapToAction ?? x.Name)
                    && !x.IsGenericMethod
                    && x.GetParameters().All(y => parameters.ContainsKey(y.Name) && CanParse(parameters[y.Name], y.ParameterType))
                    && x.GetParameters().Length <= parameters.Count)
                .FirstOrDefault();

            return method;
        }

        internal static IEnumerable<PropertyInfo> GetFlashVariableProperties(Type type)
        {
            var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
                .Where(x => x.CanRead
                    && x.GetGetMethod().IsPublic
                    && x.GetIndexParameters().Length == 0
                    && Attribute.IsDefined(x, typeof(FlashVariableAttribute))
                    && (!x.IsSpecialName || x.Name.IsValidJSVariableName()));

            return properties;
        }

        internal static IEnumerable<AccessRuleAttribute> GetAccessRuleAttrubutes(MemberInfo method)
        {
            return Attribute.GetCustomAttributes(method, typeof(AccessRuleAttribute))
                .Concat(Attribute.GetCustomAttributes(method.DeclaringType, typeof(AccessRuleAttribute)))
                .Cast<AccessRuleAttribute>();
        }

        internal static bool CheckMemberAccessForPrincipal(IPrincipal user, MemberInfo prop)
        {
            return Helpers.CheckPrincipalAgainstRules(user, GetAccessRuleAttrubutes(prop));
        }

        internal static T GetAttributeInfo<T>(this MemberInfo member) where T : Attribute
        {
            return ((T)Attribute.GetCustomAttribute(member, typeof(T)));
        }

        internal static bool CanParse(string str, Type type)
        {
            if (type == typeof(string))
            {
                return true;
            }
            else
            {
                var converter = TypeDescriptor.GetConverter(type);
                if (converter != null)
                {
                    try
                    {
                        converter.ConvertFromString(str);
                        return true;
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
        }

        internal static object Parse(string str, Type type)
        {
            if (type == typeof(string))
            {
                return str;
            }
            else
            {
                return TypeDescriptor.GetConverter(type).ConvertFromString(str);
            }
        }
    }
}
